//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.eResearch.RuntimeServices.Monitoring
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Workflow.ComponentModel;
    using System.Workflow.Runtime.Tracking;
    using Microsoft.Research.eResearch.RuntimeServices.Blackboard;
    using Microsoft.Research.eResearch.RuntimeServices.Common;
    using Microsoft.Research.eResearch.RuntimeServices.Ontology;

    public class MonitoringService : TrackingService
    {
        private Dictionary<string, Type> typeLookupTable = new Dictionary<string, Type>();

        /// <summary>
        /// Gets the available monitor concepts.
        /// </summary>
        /// <value>The available monitor concepts.</value>
        public List<string> AvailableMonitorConcepts
        {
            get
            {
                return typeLookupTable.Keys.ToList();
            }
        }

        /// <summary>
        /// Finds the monitor type for the specified concept.
        /// </summary>
        /// <param name="concept">The concept.</param>
        /// <returns>The type of the IResourceMonitor.</returns>
        public Type FindMonitorTypeForConcept(string concept)
        {
            if (typeLookupTable.ContainsKey(concept))
            {
                return typeLookupTable[concept];
            }

            return null;
        } 

        protected override void Start()
        {
            base.Start();

            InitializeTypeLookupTable();
        }

        protected override void OnStarted()
        {
            base.OnStarted();

            // Make sure that other necessary services are present
            this.Runtime.GetBlackboardService();
            this.Runtime.GetOntologyMappingService();
        }

        protected override TrackingProfile GetProfile(Guid workflowInstanceId)
        {
            return GetDefaultProfile();
        }

        protected override TrackingProfile GetProfile(Type workflowType, Version profileVersionId)
        {
            return GetDefaultProfile();
        }

        protected override TrackingChannel GetTrackingChannel(TrackingParameters parameters)
        {
            return new MonitoringChannel(this.Runtime, this, parameters);
        }

        protected override bool TryGetProfile(Type workflowType, out TrackingProfile profile)
        {
            profile = GetDefaultProfile();
            return true;
        }

        protected override bool TryReloadProfile(Type workflowType, Guid workflowInstanceId, out TrackingProfile profile)
        {
            profile = GetDefaultProfile();
            return true;
        }

        private static TrackingProfile GetDefaultProfile()
        {
            TrackingProfile profile = new TrackingProfile();
            profile.Version = new Version(1, 0, 0, 0);

            ActivityTrackPoint activityTrackPoint = new ActivityTrackPoint();
            ActivityTrackingLocation location = new ActivityTrackingLocation(typeof(Activity), true, WorkflowRuntimeHelper.AllActivityExecutionStatus);
            activityTrackPoint.MatchingLocations.Add(location);
            profile.ActivityTrackPoints.Add(activityTrackPoint);

            WorkflowTrackPoint workflowTrackPoint = new WorkflowTrackPoint();
            workflowTrackPoint.MatchingLocation = new WorkflowTrackingLocation(WorkflowRuntimeHelper.AllTrackingWorkflowEvents);
            profile.WorkflowTrackPoints.Add(workflowTrackPoint);

            return profile;
        }

        private void InitializeTypeLookupTable()
        {
            Assembly assembly = Assembly.GetExecutingAssembly();
            foreach (Type monitorType in assembly.GetTypes())
            {
                if (typeof(IResourceMonitor).IsAssignableFrom(monitorType))
                {
                    IEnumerable<MonitorConceptAttribute> attributes = monitorType.GetCustomAttributes(true).OfType<MonitorConceptAttribute>();
                    if (attributes.Count() > 0)
                    {
                        // 1 attribute was found (not more than 1 since AllowMultiple=false)
                        string conceptName = attributes.First().Concept;
                        if (!typeLookupTable.ContainsKey(conceptName))
                        {
                            typeLookupTable.Add(conceptName, monitorType);
                        }
                    }
                }
            }
        }
    }
}
